package com.yanqu.road.server.gameplayer.module.cricket.model;

import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.cricket.config.CricketConfig;
import com.yanqu.road.entity.cricket.helper.AddHpResult;
import com.yanqu.road.entity.enums.eSkillType;
import com.yanqu.road.pb.cricket.CricketProto;
import com.yanqu.road.server.gameplayer.module.cricket.CricketMgr;
import com.yanqu.road.server.gameplayer.module.cricket.battle.CricketGame;
import com.yanqu.road.server.gameplayer.module.cricket.battle.eCricketBattleRoundStep;
import com.yanqu.road.server.manger.config.SkillMgr;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class BattleData {

    public static BattleData getInstance(CricketBattleData cricketBattleData) {
        return new BattleData(cricketBattleData);
    }

    public BattleData(CricketBattleData cricketBattleData) {
        List<SkillData> skillDataList = new ArrayList<>();
        List<SkillEffect> skillEffectList = cricketBattleData.getSkillEffectList();
        for (SkillEffect skillEffect : skillEffectList) {
            SkillData skillData = SkillData.getInstance(skillEffect);
            skillData.setFromUserId(cricketBattleData.getUserId());
            skillDataList.add(skillData);
        }

        this.baseAtk = cricketBattleData.getProperty().getAtk();
        this.power = cricketBattleData.getProperty().getPower();

        long hp = cricketBattleData.getProperty().getHp();

        this.skillDataList = skillDataList;
        this.hp = hp;
        this.maxHp = hp;
        this.userId = cricketBattleData.getUserId();
        this.fightScareNum = CricketMgr.getCricketFightScareNumMax();
        this.cricketId = cricketBattleData.getCricketId();
        CricketConfig cricketConfig = CricketMgr.getConfig().getCricketConfig(this.cricketId);
        String attackSkills = cricketConfig.getAttackSkills();
        String[] split = attackSkills.split("\\|");
        for (String s : split) {
            String[] split1 = s.split(";");
            if (split1.length != 2) {
                continue;
            }
            int i = Integer.parseInt(split1[0]);
            SkillInfo skillInfo = SkillMgr.getSkillInfo(i);
            if (skillInfo == null) {
                continue;
            }
            SkillData skillData = null;
            for (SkillData data : this.skillDataList) {
                if (data.getSkillId() == i) {
                    skillData = data;
                    break;
                }
            }
            if (null == skillData) {
                SkillEffect skillEffect = SkillEffect.getInstance(skillInfo);
                skillData = SkillData.getInstance(skillEffect);
            }

            int weight = Integer.parseInt(split1[1]);
            WeightSkillData weightSkillData = WeightSkillData.getInstance();
            weightSkillData.setWeight(weight);
            weightSkillData.setSkillData(skillData);
            this.weightSkillDataList.add(weightSkillData);

            this.param = 0;
            this.param2 = 0;
        }
    }


    private long userId;

    private int cricketId;

    private List<WeightSkillData> weightSkillDataList = new ArrayList<>();

    private long hp;

    private long maxHp;


    //基础攻击
    private long baseAtk;

    private long addAtk;
    //只生效一回合的
    private Map<Integer, RoundAtkInfo> addRoundAtkMap = new HashMap<>();

    private long power;

    private List<SkillData> skillDataList;

    /**
     * 剩余打牙的次数
     */
    private int fightScareNum;

    /**
     * 怯场打牙的冷却时间
     */

    private int fightScareColdDown;

    /**
     * 一共怯场次数
     */
    private int totalFightScareNum;

    /**
     * 是否投降
     */
    private boolean surrender;

    /**
     * 冻住回合数
     */

    private int freeze;

    private int freezeSkillId;

    /**
     * 通用参数。
     */
    private int param;

    /**
     * 通用参数2
     */
    private long param2;

    /**
     * 每回合可攻击次数
     */
    private int attTime = 1;

    public long getUserId() {
        return userId;
    }

    public void setUserId(long userId) {
        this.userId = userId;
    }

    public long getHp() {
        return hp;
    }

    public void setHp(long hp) {
        this.hp = hp;
    }

    public int getParam() {
        return param;
    }

    public void setParam(int param) {
        this.param = param;
    }

    public void addParam(int param) {
        this.param += param;
    }

    public long getParam2() {
        return param2;
    }

    public void setParam2(long param2) {
        this.param2 = param2;
    }

    public void addParam2(long param2) {
        this.param2 += param2;
    }

    public AddHpResult addHp(long value) {
        AddHpResult addHpResult = AddHpResult.getInstance();
        addHpResult.setValue(value);
        if (value < 0) {
            if (this.hp + value <= 0) {
                long hp = 0;
                long realValue = this.hp;
                boolean killFlag = true;

                //技能处理，孙大圣躲避致命伤害
                for (SkillData skillData : this.skillDataList) {
                    if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill251.getValue()) {
                        //判断是否还有救命毫毛
                        int totalFur = skillData.getSkillEffect().getP1();//毫毛总数
                        int lostFur = this.getParam();//消耗的毫秒
                        int currentFur = Math.max(totalFur - lostFur, 0);//当前毫毛
                        if (currentFur > 0) {
                            //躲避致命伤害
                            this.setParam(lostFur + 1);
                            hp = realValue;
                            realValue = 0;
                            killFlag = false;
                            addHpResult.setReduceHpEffectSkillId(skillData.getSkillId());
                            addHpResult.setMissFlag(true);
                        }
                    }
                }

                this.hp = hp;
                addHpResult.setRealValue(realValue);
                addHpResult.setKill(killFlag);
            } else {
                this.hp = this.hp + value;
                addHpResult.setRealValue(value);
            }
        } else {
            if (this.hp + value > this.maxHp) {
                addHpResult.setRealValue(this.maxHp - this.hp);
                this.hp = this.maxHp;
            } else {
                this.hp = this.hp + value;
                addHpResult.setRealValue(value);
            }
        }
        return addHpResult;
    }

    /**
     * 增加血量上限
     * @param value
     */
    public long addMapHp(long value) {
        this.maxHp = this.maxHp + value;
        return this.maxHp;
    }

    public void addPower(long value) {
        this.power = this.power + value;
        //气势最低值是1
        if (this.power < 1) {
            this.power = 1;
        }
    }

    public List<SkillData> getSkillDataList() {
        return skillDataList;
    }

    public void setSkillDataList(List<SkillData> skillDataList) {
        this.skillDataList = skillDataList;
    }


    /**
     * 是否还活着
     *
     * @return
     */
    public boolean isAlive() {
        return hp > 0;
    }


    public boolean isOver() {
        if (!this.isAlive()) {
            return true;
        }
        if (this.isSurrender()) {
            return true;
        }
        return false;
    }


    /**
     * 当时回合能施放的技能
     *
     * @return
     */
    public SkillData getAttackRoundSkill() {
        int totalAttackSkillWeight = 0;

        Random random = new Random();
        List<WeightSkillData> weightSkillDataListNew = new ArrayList<>();
        for (WeightSkillData weightSkillData : this.weightSkillDataList) {
            if (weightSkillData.getSkillData().getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill160.getValue() ||
                    weightSkillData.getSkillData().getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill161.getValue() ||
                    weightSkillData.getSkillData().getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill162.getValue()) {
                if (weightSkillData.getSkillData().getCoolingDown() <= 0) {
                    ////神灵攻击,每过N回合释放,神灵攻击释放时,不释放其他攻击方式
                    weightSkillData.getSkillData().effectAmountInc();
                    return weightSkillData.getSkillData();
                }
            }
            int weight = weightSkillData.getWeight();
            int addWeight = 0;
            SkillEffect skillEffect = weightSkillData.getSkillData().getSkillEffect();
            for (SkillData skillData : this.getSkillDataList()) {
                if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill141.getValue()) {
                    if (skillEffect.getP4() == skillData.getSkillEffect().getP2()) {
                        BigDecimal bigDecimal = BigDecimal.valueOf(weight).multiply(BigDecimal.valueOf(skillData.getSkillEffect().getP1())).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
                        addWeight = addWeight + bigDecimal.intValue();
                    }
                } else if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill163.getValue()) {
                    if (skillData.getEffectRound() > 0 && skillEffect.getP4() == skillData.getSkillEffect().getP2()) {
                        //该技能生效，无法释放指定的攻击方式
                        weight = 0;
                        continue;
                    }
                }
            }

            weight = weight + addWeight;
            if (weight > 0) {
                totalAttackSkillWeight = totalAttackSkillWeight + weight;
                WeightSkillData weightSkillDataNew = WeightSkillData.getInstance();
                weightSkillDataNew.setWeight(totalAttackSkillWeight);
                weightSkillDataNew.setSkillData(weightSkillData.getSkillData());
                weightSkillDataListNew.add(weightSkillDataNew);
            }
        }
        if  (totalAttackSkillWeight > 0) {
            int i = random.nextInt(totalAttackSkillWeight);
            for (WeightSkillData weightSkillData : weightSkillDataListNew) {
                if (i < weightSkillData.getWeight()) {
                    return weightSkillData.getSkillData();
                }
//            i = i - weightSkillData.getWeight();
            }
        }

        return null;
    }


    public long getMaxHp() {
        return this.maxHp;
    }

    public int getHpRatio() {
        int hpRatio = BigDecimal.valueOf(this.getHp()).multiply(BigDecimal.valueOf(1000)).divide(BigDecimal.valueOf(this.getMaxHp()), 8, RoundingMode.DOWN).intValue();
        return hpRatio;
    }

    /**
     * 获取损失的血量
     * @return
     */
    public long getLossHp() {
        return this.getMaxHp() - this.getHp();
    }

    public long getAttack(BattleData target) {
        int hpRatio = getHpRatio();
        long addAttack = 0;

        for (SkillData skillData : this.getSkillDataList()) {
            if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill148.getValue()) {
                if (hpRatio < skillData.getSkillEffect().getP2()) {
                    long value = BigDecimal.valueOf(this.baseAtk).multiply(BigDecimal.valueOf(skillData.getSkillEffect().getP1())).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN).longValue();
                    addAttack = addAttack + value;
                }
            }

            if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill156.getValue()) {
                long value = BigDecimal.valueOf(this.baseAtk).multiply(BigDecimal.valueOf(skillData.getSkillEffect().getP1())).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN).longValue();
                addAttack = addAttack + value;
            }

            //孙大圣分身法术增加攻击
            if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill251.getValue()) {
                int totalFur = skillData.getSkillEffect().getP1();//毫毛总数
                int lostFur = this.param;//消耗的毫毛
                int currentFur = Math.max(totalFur - lostFur, 0);//当前毫毛
                //每根毫毛提供n%攻击加成。
                BigDecimal addAttRate = BigDecimal.valueOf(skillData.getSkillEffect().getP2()).multiply(BigDecimal.valueOf(currentFur)).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN);
                long value = BigDecimal.valueOf(this.baseAtk).multiply(addAttRate).longValue();
                //增加攻击
                addAttack = addAttack + value;
            }
        }

        for (SkillData skillData : target.getSkillDataList()) {
            if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill156.getValue()) {
                long value = BigDecimal.valueOf(this.baseAtk).multiply(BigDecimal.valueOf(skillData.getSkillEffect().getP2())).divide(BigDecimal.valueOf(1000), 8, RoundingMode.DOWN).longValue();
                addAttack = addAttack + value;
            }
        }


        long value = this.baseAtk + addAttack + this.addAtk + getRoundAtk();
        if (value < 1) {
            value = 1;
        }
        return value;
    }

    public long getRoundAtk() {
        long roundAtk = 0;
        for (RoundAtkInfo roundAtkInfo : this.addRoundAtkMap.values()) {
            if (roundAtkInfo.getRoundCount() == 0) {
                continue;
            }
            roundAtk += roundAtkInfo.getAddAtk();
        }
        return roundAtk;
    }

    public long getPower() {
        if (this.power < 1) {
            return 1;
        }
        return this.power;
    }

    public CricketProto.CricketBattleUserDataTemp.Builder getBattleUserData(BattleData target) {
        CricketProto.CricketBattleUserDataTemp.Builder builder = CricketProto.CricketBattleUserDataTemp.newBuilder();
        builder.setUserId(this.getUserId());
        builder.setMaxHp(this.getMaxHp());
        builder.setHp(this.getHp());
        builder.setPower(this.getPower());
        builder.setAtk(this.getAttack(target));
        for (SkillData skillData : this.getSkillDataList()) {
            builder.addSkill(skillData.toBattleSkillDataBuilder());
        }
        return builder;
    }


    public SkillEffect getSkillEffect(int skillId) {
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getSkillId() == skillId) {
                return skillData.getSkillEffect();
            }
        }
        return null;
    }

    public int getAttTime() {
        return attTime;
    }

    public void setAttTime(int attTime) {
        this.attTime = attTime;
    }

    public int getFightScareNum() {
        return fightScareNum;
    }

    public void setFightScareNum(int fightScareNum) {
        this.fightScareNum = fightScareNum;
    }

    public boolean isSurrender() {
        return surrender;
    }

    public void setSurrender(boolean surrender) {
        this.surrender = surrender;
    }

    public int getFightScareColdDown() {
        return fightScareColdDown;
    }

    public void setFightScareColdDown(int fightScareColdDown) {
        this.fightScareColdDown = fightScareColdDown;
    }

    public int getFreeze() {
        return freeze;
    }

    public void setFreeze(int freeze) {
        this.freeze = freeze;
    }

    public long getAddAttack() {
        return this.addAtk;
    }

    public void setAddAttack(long addAttack) {
        this.addAtk = addAttack;
    }

    public long getBaseAtk() {
        return baseAtk;
    }

    public int getTotalFightScareNum() {
        return totalFightScareNum;
    }

    public void setTotalFightScareNum(int totalFightScareNum) {
        this.totalFightScareNum = totalFightScareNum;
    }

    public int getFreezeSkillId() {
        return freezeSkillId;
    }

    public void setFreezeSkillId(int freezeSkillId) {
        this.freezeSkillId = freezeSkillId;
    }

    public void setAddRoundAtk(int skillId, int roundCount, long addAtk) {
        RoundAtkInfo roundAtkInfo = this.addRoundAtkMap.get(skillId);
        if (null == roundAtkInfo) {
            roundAtkInfo = new RoundAtkInfo();
            roundAtkInfo.setSkillId(skillId);
            this.addRoundAtkMap.put(skillId, roundAtkInfo);
        }
        roundAtkInfo.setAddAtk(addAtk);
        roundAtkInfo.setRoundCount(roundCount);
    }

    /**
     * 减回合计数
     */
    public void roundAtdDecRound() {
        for (RoundAtkInfo roundAtkInfo : this.addRoundAtkMap.values()) {
            if (roundAtkInfo.getRoundCount() <= 0) {
                continue;
            }
            roundAtkInfo.setRoundCount(roundAtkInfo.getRoundCount() - 1);
        }
    }

    public void resetSkillCoolingDown(int skillId) {
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getSkillId() == skillId) {
                skillData.setCoolingDown(0);
                return;
            }
        }
    }

    //是否触发复活
    public void checkReviveBySkill165(CricketProto.CricketAttackRound.Builder attackRoundBuilder, int step, CricketGame game, long lastFrameId ) {
        if (this.isAlive()) {
            return;
        }
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getSkillEffect().getSkillType() == eSkillType.CricketBattleSkill165.getValue()) {
                if (skillData.getEffectAmount() >= skillData.getSkillEffect().getP4()) {
                    //超过重生次数
                    return;
                }
                long exHpMulti = skillData.getSkillEffect().getP1() + this.getSkillEffectAmount(skillData.getSkillEffect().getP3()) * skillData.getSkillEffect().getP2();
                long reviveHp = BigDecimal.valueOf(this.getMaxHp()).multiply(BigDecimal.valueOf(exHpMulti)).divide(BigDecimal.valueOf(1000), 8, RoundingMode.UP).longValue();
                CricketProto.CricketBattleFrame.Builder newBattleFrameBuilder = game.newBattleFrameBuilder();
                newBattleFrameBuilder.setActionUserId(this.getUserId());
                newBattleFrameBuilder.setTargetUserId(this.getUserId());
                newBattleFrameBuilder.setSkillId(skillData.getSkillId());
                AddHpResult addHpResult = this.addHp(reviveHp);
                newBattleFrameBuilder.setAttack(addHpResult.getValue());
                newBattleFrameBuilder.setIsKill(addHpResult.isKill());
                newBattleFrameBuilder.setFromBattleFrameId(lastFrameId);
                game.fillRemainHp(newBattleFrameBuilder);
                attackRoundBuilder.addAttack(newBattleFrameBuilder);
//                if (step == eCricketBattleRoundStep.StartRound.getValue()) {
//                    attackRoundBuilder.addStartRound(newBattleFrameBuilder);
//                } else if (step == eCricketBattleRoundStep.Attack.getValue()) {
//                    attackRoundBuilder.addAttack(newBattleFrameBuilder);
//                } else if (step == eCricketBattleRoundStep.AfterAttack.getValue()) {
//                    attackRoundBuilder.addAfterAttack(newBattleFrameBuilder);
//                } else if (step == eCricketBattleRoundStep.EndRound.getValue()) {
//                    attackRoundBuilder.addEndRound(newBattleFrameBuilder);
//                }
                skillData.effectAmountInc();
            }
        }
    }

    public int getSkillEffectAmount(int skillId) {
        for (WeightSkillData weightSkillData : this.weightSkillDataList) {
            if (weightSkillData.getSkillData().getSkillId() == skillId) {
                return weightSkillData.getSkillData().getEffectAmount();
            }
        }
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getSkillId() == skillId) {
                return skillData.getEffectAmount();
            }
        }
        return 0;
    }

    //减少技能冷却回合
    public void decSkillCoolingDown(int skillId, int decNum) {
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getSkillId() == skillId) {
                if (skillData.getCoolingDown() >= decNum) {
                    skillData.setCoolingDown(skillData.getCoolingDown() - decNum);
//                    System.out.printf("%d的回合=%d\r\n",skillData.getSkillId(),skillData.getCoolingDown());
                } else {
                    skillData.setCoolingDown(0);
                }
                return;
            }
        }
    }

    /**
     * 回合开始统一减少冷却回合一回合
     */

    public void decCoolingDownOnStartRound() {
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getCoolingDown() > 0) {
                skillData.setCoolingDown(skillData.getCoolingDown() - 1);
//                System.out.printf("玩家%d回合开始 技能%d,回合=%d\r\n", skillData.getFromUserId(), skillData.getSkillId(), skillData.getCoolingDown());
            } else {
                skillData.setCoolingDown(0);
            }
        }
    }

    /**
     * 回合结束统一检查冷却
     */

    public void checkCoolingDownOnEndRound() {
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getCoolingDown() <= 0 && skillData.isRelease()) {
                //释放过才要重置回合
                skillData.initCoolingDown();

//                int skillType = skillData.getSkillEffect().getSkillType();
//                if (skillType == eSkillType.CricketBattleSkill160.getValue() ||
//                        skillType == eSkillType.CricketBattleSkill161.getValue() ||
//                        skillType == eSkillType.CricketBattleSkill162.getValue()) {
////                    System.out.printf("玩家%d回合结束 技能%d,回合=%d\r\n", skillData.getFromUserId(),skillData.getSkillId(), skillData.getCoolingDown());
//                }
            }

            skillData.setRelease(false);
        }
    }

    /**
     * 取非0计数的技能数据
     *
     * @return CricketProto.CricketBattleSkillDataTemp
     */
    public List<CricketProto.CricketBattleSkillDataTemp> getEffectSkillDataTemp() {
        List<CricketProto.CricketBattleSkillDataTemp> msglist = new ArrayList<>();
        for (SkillData skillData : this.skillDataList) {
            if (skillData.getOverlay() == 0 && skillData.getEffectRound() == 0 && skillData.getCoolingDown() == 0) {
                continue;
            }
            msglist.add(CricketProto.CricketBattleSkillDataTemp.newBuilder().setFromUserId(getUserId()).setSkillId(skillData.getSkillId()).
                    setOverlay(skillData.getOverlay()).setEffectRound(skillData.getEffectRound()).setCoolingDown(skillData.getCoolingDown()).build());
        }
        return msglist;
    }

    public List<CricketProto.CricketBattleSkillDataTemp> getAllSkillDataMsgTemp() {
        List<CricketProto.CricketBattleSkillDataTemp> msglist = new ArrayList<>();
        for (SkillData skillData : this.skillDataList) {
            msglist.add(CricketProto.CricketBattleSkillDataTemp.newBuilder().setFromUserId(getUserId()).setSkillId(skillData.getSkillId()).
                    setOverlay(skillData.getOverlay()).setEffectRound(skillData.getEffectRound()).setCoolingDown(skillData.getCoolingDown()).build());
        }
        return msglist;
    }

}
